package com.baihejia.common.dubbo.server.interceptor;

import com.baihejia.common.dubbo.libs.JsonHelper;
import com.baihejia.common.dubbo.server.Logger;
import com.baihejia.common.dubbo.server.cache.aop.ListCache;
import com.baihejia.common.dubbo.server.cache.aop.ListCacheAop;
import com.baihejia.common.dubbo.server.cache.aop.SimpleCache;
import com.baihejia.common.dubbo.server.cache.aop.SimpleCacheAop;

import org.apache.commons.lang.ArrayUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class Handler implements InvocationHandler {

    private Object object;

    public Handler(Object subject) {
        this.object = subject;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        long now = System.currentTimeMillis();
        try {

            Method[] methods = object.getClass().getDeclaredMethods();

            Map<String, Method> methodMap = new HashMap<>();
            for (Method declareMethod : methods) {
                methodMap.put(declareMethod.getName(), declareMethod);
            }
            Method realMethod = methodMap.get(method.getName());

            Annotation[] annotations = realMethod.getDeclaredAnnotations();

            if (ArrayUtils.isEmpty(annotations)) {
                return method.invoke(object, args);
            }

            Map<Class, Annotation> annotationMap = new HashMap<>();
            for (Annotation annotation : annotations) {
                annotationMap.put(annotation.annotationType(), annotation);
            }
            Set<Class> keys = annotationMap.keySet();
            if (keys.contains(ListCache.class)) {
                return ListCacheAop.handle(object, method, args, (ListCache) annotationMap.get(ListCache.class));
            }else if (keys.contains(SimpleCache.class)) {
                return SimpleCacheAop.handle(object, method, args, (SimpleCache) annotationMap.get(SimpleCache.class));
            } else {
                return method.invoke(object, args);
            }

        } finally {
            Logger.info(String.format("%s.%s, cost:%s, params:%s", method.getDeclaringClass().getName(), method.getName(), System.currentTimeMillis() - now, JsonHelper.toString(args)));
        }
    }
}
